/*
 * This file is part of the Shell Library.
 *
 * Copyright (c) 2024, ark, <345473553@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Function: Initialize function and other general function.
 */

/**************************************************************************************************
 *                                            INCLUDES
 **************************************************************************************************/
#include "shell.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "elog.h"
#include "re.h"

/*********************************************************************
 * TYPEDEFS
 */

/*********************************************************************
 * EXTERNAL VARIABLES
 */

/*********************************************************************
 * VARIABLES
 */
uint8_t _u8CmdLen;
uint8_t _u8ParamCount;
char *_u8psParmPtr[SHELL_PARM_MAX];
char _u8sCmd[SHELL_COMMAND_MAX];
char _u8sDesp[SHELL_CUSTOM_DESP_MAX];

#if(SHELL_NEED_LOGIN==1)
uint8_t _u8logined = false;
#endif

/*********************************************************************
 * FUNCTIONS —— 内置指令
 *********************************************************************/
#if(SHELL_NEED_LOGIN==1)
uint8_t shell_parse_login(uint8_t argc, const char *argv[])
{// 直接输入login指令为退出登录
  if(argc > 2)
    return SHELL_ERR_PARAM;
  if(argc==1)
    _u8logined = false;
  else if(strcmp(argv[1],SHELL_LOGIN_KEY)==0)
    _u8logined = true;
  
  return SHELL_OK;
}
#endif

uint8_t shell_parse_help(uint8_t argc, const char *argv[])
{
  int i=0;
  elog_raw("cmd   param\r\n");
  while(_xshellCmds[i].func!=NULL){
    elog_raw(_xshellCmds[i++].desp);
  }
  
  return SHELL_OK;
}

uint8_t shell_parse_int(uint8_t argc, const char *argv[])
{
  int len,val;
  uint32_t adr;
  if(argc<3 || argc>4)
    return SHELL_ERR_PARAM;
  if( SHELL_OK != verify_hex_32b(argv[1]))
    return SHELL_ERR_PARAM;
  if( SHELL_OK != verify_dec_u8(argv[2]))
    return SHELL_ERR_PARAM;
  if( argc==4 && SHELL_OK != verify_dec_int(argv[3]))
    return SHELL_ERR_PARAM;
  
  adr = convert_hex_to_u32(argv[1]);
  len = atoi(argv[2]);
  if(argc==3){ // 显示值
    if(len==1) elog_raw("%d\r\n",*((int8_t*)adr));
    else if(len==2) elog_raw("%d\r\n",*((int16_t*)adr));
    else if(len==4) elog_raw("%d\r\n",*((int32_t*)adr));
  }else{ // 设置值
    val = atoi(argv[3]);
    if(len==1) *((int8_t*)adr)=(int8_t)val;
    else if(len==2) *((int16_t*)adr)=(int16_t)val;
    else if(len==4) *((int32_t*)adr)=(int32_t)val;
  }
  
  return SHELL_OK;
}

uint8_t shell_parse_uint(uint8_t argc, const char *argv[])
{
  int len,val;
  uint32_t adr;
  if(argc<3 || argc>4)
    return SHELL_ERR_PARAM;
  if( SHELL_OK != verify_hex_32b(argv[1]))
    return SHELL_ERR_PARAM;
  if( SHELL_OK != verify_dec_u8(argv[2]))
    return SHELL_ERR_PARAM;
  if( argc==4 && SHELL_OK != verify_dec_u32(argv[3]))
    return SHELL_ERR_PARAM;
  
  adr = convert_hex_to_u32(argv[1]);
  len = atoi(argv[2]);
  if(argc==3){ // 显示值
    if(len==1) elog_raw("%u\r\n",*((uint8_t*)adr));
    else if(len==2) elog_raw("%u\r\n",*((uint16_t*)adr));
    else if(len==4) elog_raw("%u\r\n",*((uint32_t*)adr));
    else return SHELL_ERR_PARAM;
  }else{ // 设置值
    val = atoi(argv[3]);
    if(len==1) *((uint8_t*)adr)=(uint8_t)val;
    else if(len==2) *((uint16_t*)adr)=(uint16_t)val;
    else if(len==4) *((uint32_t*)adr)=(uint32_t)val;
    else return SHELL_ERR_PARAM;
  }
  
  return SHELL_OK;
}

uint8_t shell_parse_hex(uint8_t argc, const char *argv[])
{
  uint8_t *ptr,buf[98],val;
  int i=0,len;
  uint32_t adr;
  if(argc<3 || argc>4)
    return SHELL_ERR_PARAM;
  if( SHELL_OK != verify_hex_32b(argv[1]))
    return SHELL_ERR_PARAM;
  if( SHELL_OK != verify_dec_u8(argv[2]))
    return SHELL_ERR_PARAM;
  if( argc==4 && SHELL_OK != verify_hex_u8s(argv[3]))
    return SHELL_ERR_PARAM;
  
  adr = convert_hex_to_u32(argv[1]);
  len = atoi(argv[2]);
  if(len>48 || len<1)
    return SHELL_ERR_PARAM;
  if(argc==3){ // 显示值
    strcpy((char*)buf,"0x");
    ptr = buf +2;
    while(len--){
      ptr = convert_u8_to_hex(ptr,*(((uint8_t*)adr)+i));
      *ptr++ = ' ';i++;
    }
    *ptr = '\0';
    elog_raw("%s\r\n",(const char*)buf);
  }else{ // 设置值
    i = 2;
    ptr = (uint8_t*)adr;
    while(argv[3][i]!='\0'){
      val = convert_hex_to_u8( argv[3] + i );
      *ptr++ = val;
      i += 2;
    }
  }
  
  return SHELL_OK;
}
#if(SHELL_NEED_FLOAT==1)
uint8_t shell_parse_flt(uint8_t argc, const char *argv[])
{
  uint32_t adr;
  float val;
  if(argc<3 || argc>4)
    return SHELL_ERR_PARAM;
  if( SHELL_OK != verify_hex_32b(argv[1]))
    return SHELL_ERR_PARAM;
  if( SHELL_OK != verify_dec_u8(argv[2]))
    return SHELL_ERR_PARAM;
  if( argc==4 && SHELL_OK != verify_dec_flt(argv[3]))
    return SHELL_ERR_PARAM;
  
  adr = convert_hex_to_u32(argv[1]);
  if(atoi(argv[2])!=4)
    return SHELL_ERR_PARAM;
  if(argc==3){ // 显示值
    elog_raw("%f\r\n",*((float*)adr));
  }else{ // 设置值
    sscanf(argv[3], "%f", &val);
    *((float*)adr)=val;
  }
  
  return SHELL_OK;
}
#endif

uint8_t shell_parse_str(uint8_t argc, const char *argv[])
{
  int len;
  uint32_t adr;
  if(argc<3 || argc>4)
    return SHELL_ERR_PARAM;
  if( SHELL_OK != verify_hex_32b(argv[1]))
    return SHELL_ERR_PARAM;
  if( SHELL_OK != verify_dec_u8(argv[2]))
    return SHELL_ERR_PARAM;
  // if( argc==4 && SHELL_OK != verify_hex_u8s(argv[3]))
  //   return SHELL_ERR_PARAM;
  
  adr = convert_hex_to_u32(argv[1]);
  len = atoi(argv[2]);
  if(argc==3){ // 显示值
    elog_raw("%s\r\n",(const char*)adr);
  }else{ // 设置值
    strncpy((char*)adr,argv[3],len);
  }
  
  return SHELL_OK;
}

typedef struct SymbolItem{
  uint32_t adr;
  uint8_t  typ;
} xSymbolItem;
/*
 * cmd: MD [adr|typ|len:0xXXXXXXXXf4] ...
 * desp: show multi memory and register datas*/
uint8_t shell_parse_md(uint8_t argc, const char *argv[])
{
  static xSymbolItem _syms[SHELL_CMD_MAX];
  static uint8_t     _sym_cnt;
  char *ptr,buf[SHELL_COMMAND_MAX];
  uint8_t typ1,typ2;
  int len,seek=0;
  uint32_t adr;
  if(argc==1){
    if(_sym_cnt==0)
      return SHELL_ERR_PARAM;
    for(int i=0; i<_sym_cnt; i++){
      typ1 = _syms[i].typ & 0xf0;
      typ2 = _syms[i].typ & 0x0f;
      if(typ1==0x10){ // 有符号整数
        if(typ2==1) // i8类型
          len = sprintf(buf+seek,"%d,",*((int8_t*)(_syms[i].adr)));
        else if(typ2==2) // i16类型
          len = sprintf(buf+seek,"%d,",*((int16_t*)(_syms[i].adr)));
        else if(typ2==4) // i32类型
          len = sprintf(buf+seek,"%d,",*((int32_t*)(_syms[i].adr)));
      }else if(typ1==0x20){ // 无符号整数
        if(typ2==1) // i8类型
          len = sprintf(buf+seek,"%u,",*((uint8_t*)(_syms[i].adr)));
        else if(typ2==2) // i16类型
          len = sprintf(buf+seek,"%u,",*((uint16_t*)(_syms[i].adr)));
        else if(typ2==4) // i32类型
          len = sprintf(buf+seek,"%u,",*((uint32_t*)(_syms[i].adr)));
      }
#if(SHELL_NEED_FLOAT==1)
      else if(typ1==0x30){ // 浮点数
        if(typ2==4) // float类型
          len = sprintf(buf+seek,"%f,",*((float*)(_syms[i].adr)));
        else
          return SHELL_ERR_PARAM;
      }
#endif
      seek += len;
    }
    buf[seek-1]='\0';
    elog_raw("%s\r\n",buf);

    return SHELL_NOECHO;
  }
  _sym_cnt = 0;
  for(int i=1; i<argc; i++){
    ptr = (char*)argv[i];
    len = strlen(ptr);
    if(len!=12)
      goto _md_error;
    re_t rt = re_compile("^0x[0-9a-fA-F]+[GIU][124]$");
    if( re_matchp(rt, (const char*)ptr, &len) == -1 )
      goto _md_error;
    typ1 = ptr[10];typ2 = ptr[11];ptr[10] = '\0';
    adr = convert_hex_to_u32(ptr);
    _syms[_sym_cnt].adr = adr;
    if(typ1=='I'){ // 有符号整数
      _syms[_sym_cnt].typ = 1<<4;
      if(typ2=='1'){ // i8类型;
        _syms[_sym_cnt].typ+=1;
        len = sprintf(buf+seek,"%d,",*((int8_t*)adr));
      }else if(typ2=='2'){ // i16类型
        _syms[_sym_cnt].typ+=2;
        len = sprintf(buf+seek,"%d,",*((int16_t*)adr));
      }else if(typ2=='4'){ // i32类型
        _syms[_sym_cnt].typ+=4;
        len = sprintf(buf+seek,"%d,",*((int32_t*)adr));
      }else
        goto _md_error;
    }else if(typ1=='U'){ // 无符号整数
      _syms[_sym_cnt].typ = 2<<4;
      if(typ2=='1'){ // i8类型
        _syms[_sym_cnt].typ+=1;
        len = sprintf(buf+seek,"%u,",*((uint8_t*)adr));
      }else if(typ2=='2'){ // i16类型
        _syms[_sym_cnt].typ+=2;
        len = sprintf(buf+seek,"%u,",*((uint16_t*)adr));
      }else if(typ2=='4'){ // i32类型
        _syms[_sym_cnt].typ+=4;
        len = sprintf(buf+seek,"%u,",*((uint32_t*)adr));
      }else
        goto _md_error;
    }
#if(SHELL_NEED_FLOAT==1)
    else if(typ1=='G'){ // 浮点数
      _syms[_sym_cnt].typ = 3<<4;
      if(typ2=='4'){ // float类型
        _syms[_sym_cnt].typ+=4;
        len = sprintf(buf+seek,"%f,",*((float*)adr));
      }else
        goto _md_error;
    }
#endif
    _sym_cnt++; seek += len;
  }

  buf[seek-1]='\0';
  elog_raw("%s\r\n",buf);
  
  return SHELL_NOECHO;
_md_error:
  _sym_cnt = 0;
  return SHELL_ERR_PARAM;
}

/*
 * cmd: MM <adr:0xXXXXXXXX> [data:0xXX[XXXXXX]]
 * desp: show or set the memory and register datas*/
uint8_t shell_parse_ram(uint8_t argc, const char *argv[])
{
  uint8_t  sk,vu8,*pu8,*pmem;
  uint32_t adr;
  uint8_t buf[64],prefix[]=" ";
  if(argc == 1 || argc >3)
    return SHELL_ERR_PARAM;
  else if( argc == 2){ // read the mem
    if( SHELL_OK != verify_hex_32b(argv[1]))
      return SHELL_ERR_PARAM;

    adr = convert_hex_to_u32(argv[1]);
//    elog_raw("ADDR       0 1 2 3  4 5 6 7  8 9 A B  C D E F\r\n");
    elog_raw("ADDR       3 2 1 0  7 6 5 4  B A 9 8  F E D C\r\n");
//  elog_raw("0x00000000 00000000 00000000 00000000 00000000\r\n");
    adr &= 0xfffffff0;
    pmem = (uint8_t*)adr;
    for( sk=0; sk<16; sk++ ){
      //print 1 line
      sprintf((char*)buf,"0x%8x",(uint32_t)pmem);
      pu8 = convert_u8s_to_hex(buf+10, pmem, 4, 4, prefix);
      memcpy(pu8,"\r\n\0",3);
      elog_raw((const char*)buf);

      // prepare to the next line
      pmem += 16;
    }
  }else{ // write the mem
    if( SHELL_OK != verify_hex_32b(argv[1]))
      return SHELL_ERR_PARAM;
    adr = convert_hex_to_u32(argv[1]);
    sk = 2;
    pu8 = (uint8_t*)adr;
    while(argv[2][sk]!='\0'){
      vu8 = convert_hex_to_u8( argv[2] + sk );
      *pu8 = vu8;
      pu8++;
      sk += 2;
    }
  }

  return SHELL_OK;
}


int call(uint8_t argc, const char *argv[])
{
  uint32_t res;
  void *func; // 函数指针
  uint32_t temp[8];        /* 参数转换,使之支持了字符串 */
  // argv[1] 是函数的地址
  func = (void *)convert_hex_to_u32(argv[1]);
  // 获取参数的值
  for(int i=0; i<argc-2; i++){
    if(verify_dec_u16(argv[i+2]) == SHELL_OK)
      temp[i] = atoi((const char *)argv[i+2]);
#if(SHELL_NEED_FLOAT==1)
    else if(verify_dec_flt(argv[i+2]) == SHELL_OK)
      sscanf((const char *)argv[i+2], "%f", &temp[i]);
#endif
    else if(verify_hex_32b(argv[i+2]) == SHELL_OK)
      temp[i] = convert_hex_to_u32(argv[i+2]);
    else // 当做字符串处理
      temp[i] = (int)argv[i+2]; // 直接赋值指针
  }

  switch (argc-2){
    case 0: /* 无参数(void类型) */
        res = (*(uint32_t(*)())func)();
        break;
    case 1: /* 有1个参数 */
        res = (*(uint32_t(*)())func)(temp[0]);
        break;
    case 2: /* 有2个参数 */
        res = (*(uint32_t(*)())func)(temp[0], temp[1]);
        break;
    case 3: /* 有3个参数 */
        res = (*(uint32_t(*)())func)(temp[0], temp[1], temp[2]);
        break;
    case 4: /* 有4个参数 */
        res = (*(uint32_t(*)())func)(temp[0], temp[1], temp[2], temp[3]);
        break;
    case 5: /* 有5个参数 */
        res = (*(uint32_t(*)())func)(temp[0], temp[1], temp[2], temp[3], temp[4]);
        break;
    case 6: /* 有6个参数 */
        res = (*(uint32_t(*)())func)(temp[0], temp[1], temp[2], temp[3], temp[4], temp[5]);
        break;
    case 7: /* 有7个参数 */
        res = (*(uint32_t(*)())func)(temp[0], temp[1], temp[2], temp[3], temp[4], temp[5], temp[6]);
        break;
    case 8: /* 有8个参数 */
        res = (*(uint32_t(*)())func)(temp[0], temp[1], temp[2], temp[3], temp[4], temp[5], temp[6], temp[7]);
        break;
  }
  return res;
}

// 无返回
uint8_t shell_parse_callv(uint8_t argc, const char *argv[])
{
  call( argc, argv);
  return SHELL_OK;
}

// 十六进制显示返回的结果
uint8_t shell_parse_callh(uint8_t argc, const char *argv[])
{
  int rsp = call( argc, argv);
  elog_raw("return: 0x%08x\r\n", rsp);
  return SHELL_OK;
}

// 十进制显示返回的结果
uint8_t shell_parse_calld(uint8_t argc, const char *argv[])
{
  int rsp = call( argc, argv);
  elog_raw("return: 0x%d\r\n", rsp);
  return SHELL_OK;
}


/*********************************************************************
 * FUNCTIONS
 *********************************************************************/
uint8_t verify_hex_char( const char c )
{
  if( ((c>='0')&&(c<='9'))||((c>='A')&&(c<='F'))||((c>='a')&&(c<='f')))
    return SHELL_OK;
  else
    return SHELL_ERR;
}

uint8_t verify_dec_char( const char c )
{
  if( (c>='0')&&(c<='9') )
    return SHELL_OK;
  else
    return SHELL_ERR;
}

uint8_t verify_dec_u8( const char *p )
{
  size_t i,len;
  len = strlen( (const char *)p);
	
  if( len > 3 )
    return SHELL_ERR;
  for( i=0; i<len; i++ )
    if( SHELL_ERR == verify_dec_char(p[i]))
      return SHELL_ERR;

  return SHELL_OK;
}

uint8_t verify_dec_u16( const char *p )
{
  size_t i,len;
  len = strlen( (const char *)p);
	
  if( len > 5 )
    return SHELL_ERR;
  for( i=0; i<len; i++ )
    if( SHELL_ERR == verify_dec_char(p[i]))
      return SHELL_ERR;
  i = atoi((const char*)p);
  if(i>0xffff)
    return SHELL_ERR;

  return SHELL_OK;
}

uint8_t verify_dec_u32( const char *p )
{
  int len,seek;
  re_t rt = re_compile("^\\d+$");
	seek = re_matchp(rt, (const char*)p, &len);
  if( seek == -1 )
    return SHELL_ERR;
  return SHELL_OK;
}

uint8_t verify_dec_int( const char *p )
{
  int len,seek;
  re_t rt = re_compile("^-?\\d+$");
	seek = re_matchp(rt, (const char*)p, &len);
  if( seek == -1 )
    return SHELL_ERR;
  return SHELL_OK;
}

uint8_t verify_dec_flt( const char *p )
{
  int len,seek;
  re_t rt = re_compile("\\d+\\.\\d+");
	seek = re_matchp(rt, (const char*)p, &len);
  if( seek == -1 )
    return SHELL_ERR;
  return SHELL_OK;
}


uint8_t verify_hex_u8s( const char *p )
{
  size_t i,len;
  len = strlen( (const char *)p);
	
  if( 0 != len%2 )
    return SHELL_ERR;
  if( 0 != strncmp( (const char*)p,"0x",2))
    return SHELL_ERR;
  for( i=2; i<len; i++ )
    if( SHELL_ERR == verify_hex_char(p[i]))
      return SHELL_ERR;

  return SHELL_OK;
}


uint8_t verify_hex_16b( const char *p )
{
  uint8_t i;
  size_t len;
  len = strlen( (const char *)p);
  if( len != 6 )
    return SHELL_ERR;
  if( 0!= strncmp( (const char*)p,"0x",2))
    return SHELL_ERR;
  for( i=2; i<6; i++ )
    if( SHELL_ERR == verify_hex_char(p[i]))
      return SHELL_ERR;

  return SHELL_OK;
}


uint8_t verify_hex_32b( const char *p )
{
  uint8_t i;
  size_t len;
  len = strlen( (const char *)p);
  if( len != 10 )
    return SHELL_ERR;
  if( 0!= strncmp( (const char*)p,"0x",2))
    return SHELL_ERR;
  for( i=2; i<10; i++ )
    if( SHELL_ERR == verify_hex_char(p[i]))
      return SHELL_ERR;

  return SHELL_OK;
}

uint32_t _convert_hex_to_val( const char *p, uint8_t len )
{
  uint32_t val = 0;
  uint8_t sk=0;
  if(p[1]=='x')
    sk=2;
  while( p[sk] != '\0' && len>0 ){
    val <<= 4;
    if(p[sk]>='0' && p[sk]<='9')
      val += p[sk] - '0';
    else if(p[sk]>='A' && p[sk]<='F')
      val += 10 + p[sk] - 'A';
    else if(p[sk]>='a' && p[sk]<='f')
      val += 10 + p[sk] - 'a';
    else{
      val = 0;
      break;
    }
    sk++;len--;
  }
  return val;
}

uint32_t convert_hex_to_u32( const char *p )
{
  return _convert_hex_to_val(p,8);
}

uint8_t convert_hex_to_u8( const char *p)
{
  return (uint8_t)_convert_hex_to_val(p,2);
}

uint16_t convert_hex_to_u16( const char *p )
{
  return (uint16_t)_convert_hex_to_val(p,4);
}

static const char csTurnMap[17]="0123456789ABCDEF";
uint8_t* convert_u8_to_hex( uint8_t *ptr, uint8_t a )
{
  ptr[0] = csTurnMap[ a>>4 ];
  ptr[1] = csTurnMap[ a&0x0f ];
  return ptr+2;
}


/*typ:变量类型 num:变量数量 prefix:前缀*/
uint8_t* convert_u8s_to_hex( uint8_t *pdst, uint8_t *psrc, uint8_t typ, uint8_t num, uint8_t *prefix )
{
  uint8_t i,seek_cur=0,pfx_len;
  uint8_t ofs_max;
  int8_t j;
  uint32_t val;
  pfx_len = prefix != NULL? strlen( (const char *)prefix ):0;
  
  for( i=0; i<num; i++ ){
    if( pfx_len ){
      memcpy( pdst+seek_cur, prefix, pfx_len );
      seek_cur += pfx_len;
    }
    switch( typ ){
    case 1:
      ofs_max =2 ; val = psrc[i];
      break;
    case 2:
      ofs_max =4 ; val = ((uint16_t*)psrc)[i];
      break;
    case 4:
      ofs_max =8 ;  val = ((uint32_t*)psrc)[i];
      break;
    default :
      ofs_max = 0;
      break;
    }
    for( j=ofs_max-1; j>=0; j-- ){
      pdst[seek_cur+j]   = csTurnMap[ val & 0x0000000f ];
      val = val >> 4;
    }
    seek_cur += ofs_max ;
  }
  return pdst + seek_cur;
}

uint8_t shell_set_custom_err_desp( const char *pstr )
{
  strncpy((char*)_u8sDesp, (const char*)pstr, SHELL_CUSTOM_DESP_MAX);
  return SHELL_OK;
}

uint8_t shell_seek_next_print( uint8_t sk )
{
  const char *p;
  p = _u8sCmd;
  while( sk < _u8CmdLen ){
    if((p[sk]==' ')||(p[sk]=='\r')||(p[sk]=='\n'))
      sk++;
    else
      break;
  }

  return sk;
}

uint8_t shell_seek_next_unprint( uint8_t sk )
{
  char *p;
  uint8_t str=0,skc;
  p = _u8sCmd;
  while( sk < _u8CmdLen ){
    if(str==1){ // 字符串模式
      if(p[sk]=='\"'){ // 字符串模式结束
        sk++;p[skc]='\0';
        break;
      }else if((p[sk]=='\r')||(p[sk]=='\n')){ // 解析到异常结尾，但是字符串没有正确结束，直接返回
        p[skc]='\0';sk++;
        break;
      }else if( p[sk]=='\\'){ // 格式转换符
        sk++;
        if(p[sk]=='n') p[skc++]='\n';
        else if(p[sk]=='r') p[skc++]='\r';
        else if(p[sk]=='\"') p[skc++]='\"';
        else if(p[sk]=='\\') p[skc++]='\\';
        else if(p[sk]=='t') p[skc++]='\t';
        else if(p[sk]=='b') p[skc++]='\b';
        else if(p[sk]=='a') p[skc++]='\a';
        sk++;
      }else{
        p[skc++]=p[sk++];
      }
    }else{ // 普通模式
      if(p[sk]=='\"'){ // 解析到1个字符串
        str = 1;skc = sk;sk++;
      }else if((p[sk]!=' ')&&(p[sk]!='\r')&&(p[sk]!='\n')){
        sk++;
      }else {
        break;
      }
    }
  }

  return sk;
}

uint8_t shell_proc(uint8_t argc, const char *argv[])
{
  uint8_t resp=SHELL_ERR_UNKNOW,i=0;
  do{
    if(0 == strcmp((const char*)argv[0],_xshellCmds[i].cmd)){
      if( argc == 2 && argv[1][0]=='?'){
        elog_raw(_xshellCmds[i].desp);
        resp = SHELL_OK;
      }else{
        resp = _xshellCmds[i].func(argc, argv);
      }
      break;
    }
  }while(_xshellCmds[++i].func!=NULL);
  if(resp==SHELL_ERR_UNKNOW)
    elog_raw("error: unknown command.\r\n");

  return resp;
}

uint8_t shell_parse( void )
{
  uint8_t resp;
  uint8_t seek;
  uint8_t len;
  
  if(_u8CmdLen == SHELL_COMMAND_MAX){
    _u8CmdLen = 0;
    resp = SHELL_ERR_TOO_LONG;
    goto shell_resp;
  }

  // verify if the cmd end
  if( _u8sCmd[_u8CmdLen-1] != '\n' )
    return SHELL_OK;
  else
    _u8sCmd[_u8CmdLen] = '\0';

  // parase the cmd line
  seek = 0;
  _u8ParamCount = 0;
  while( seek < _u8CmdLen ){
    // get the cmd/parm start
    seek = shell_seek_next_print( seek );
    if( seek < _u8CmdLen ){
      _u8psParmPtr[_u8ParamCount] = _u8sCmd + seek;
      _u8ParamCount++;
    }else{
      break;
    }
    // get and update the cmd/param end
    seek = shell_seek_next_unprint( seek );
    if( seek < _u8CmdLen ){
      _u8sCmd[seek] = '\0';
      seek++;
    }
  }

  if( 0 == _u8ParamCount ) // input empty
    goto shell_exit;
  else{
#if(SHELL_NEED_LOGIN==1)
    if((_u8logined==true)||strcmp((const char*)_u8psParmPtr[0],"LOGIN")==0)
      resp = shell_proc( _u8ParamCount, (const char**)_u8psParmPtr );
    else
      goto shell_exit;
#else
    resp = shell_proc( _u8ParamCount, (const char**)_u8psParmPtr );
#endif
  }

shell_resp:
  if( resp == SHELL_OK )
    elog_raw("ok.\r\n>>");
  else if( resp == SHELL_ERR )
    elog_raw("err: unknown\r\n>>");
  else if( resp == SHELL_ERR_PARAM )
    elog_raw("err: param error\r\n>>");
  else if( resp == SHELL_ERR_TOO_LONG )
    elog_raw("err: cmd too long, max:%d cur %d\r\n>>",SHELL_COMMAND_MAX,len);
  else if( resp == SHELL_ERR_CUSTOM )
    elog_raw("err: %s\r\n>>",_u8sDesp);
shell_exit:
  _u8CmdLen = 0;

  return SHELL_OK;
}

uint8_t shell_put_u8( uint8_t c )
{
  uint8_t resp=SHELL_OK;
  
  if(_u8CmdLen < SHELL_COMMAND_MAX){
    _u8sCmd[_u8CmdLen] = c;
    _u8CmdLen++;
  }else{
    resp = SHELL_ERR_TOO_LONG;
    elog_raw("err: cmd too long, max:%d cur %d",SHELL_COMMAND_MAX,_u8CmdLen);
    _u8CmdLen = 0;
  }
  return resp;
}
  
uint8_t shell_put_buf( uint8_t *ptr, uint8_t sz )
{
  uint8_t resp;

	while(sz-->0){
    resp = shell_put_u8(*ptr);
    if(resp != SHELL_OK)
      break;
    if( *ptr == '\n' )
      break;
    ptr++;
  }
  return resp;
}
